
package com.zcp.pcsuitall;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import java.io.File;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.HashMap;

/**
 * 这个服务主要用来和client通讯。<br>
 * Service 生命周期onCreate() onStart() onDestory()三个方法，。<br>
 * 第一次启动的时候先后调用上面三个方法，当停止的时候调用onDestroy（）方法，。<br>
 * 需要注意的是当已经启动service，再次启动的时候不会调用onCreate()方法直接调用onStart()方法。<br>
 * 
 * @author Administrator
 */
public class SocketService extends Service {

    private Object object = new Object();

    /**
     * 重新设置密钥。
     */
    public String resetCipherKey() {
        // 只有在USB模式下才能重新设置密钥。
        if (startActivity.equals("PhoneServiceAllActivity")) {
            cipherKey = MyDes.getRandomStr(8);
            socketThread.setCipherKey(cipherKey);
            return cipherKey;

        } else {
            return null;
        }

    }

    /**
     * 通过指令通道发送数据给客户端。
     * 
     * @param sc
     * @param value 要发送的数据。
     * @return
     */
    public boolean sendData(SocketChannel sc, String value) {
        return socketThread.sendData(sc, MyDes.encryptDES(value, cipherKey));
    }

    /**
     * 通过指令通道发送数据给客户端。
     * 
     * @param sc
     * @param value 要发送的数据。
     * @return
     */
    public boolean sendData(SocketChannel sc, String value, String myCipherKey) {
        return socketThread.sendData(sc, MyDes.encryptDES(value, myCipherKey));
    }

    /**
     * 通过指令通道发送数据给客户端。
     * 
     * @param value 要发送的数据。
     * @return
     */
    public boolean sendData(String value) {
        return socketThread.sendData(MyDes.encryptDES(value, cipherKey));
    }

    /**
     * 用来关闭指令通道。
     * 
     * @param key
     */
    public void closeSocketChannel(SelectionKey key) {
        socketThread.closeSocketChannel(key);
    }

    /**
     * 通知线程下载准备好下载文件，这个就会通知指令线程告诉客户端可以传输数据了。
     * 
     * @param filePath
     * @param fileLength
     * @param key 其实就是端口号。
     * @param id 由client传过来的标识符，主要用来区分上传不同的文件.
     * @return
     */
    public void downLoadFile(String filePath, long fileLength, String key, String id) {
        synchronized (object) {
            boolean isCanUserSdCard = SuitUtil.isSdcardCanUser();
            // 先检查sdcard是否可用
            if (!isCanUserSdCard) {
                String message = getReadyDownLoadMessage(false, filePath, fileLength, key, 1);
                sendData(message);
                return;
            }
            // 文件路径是null或者是""
            if (filePath == null && filePath.equals("")) {
                String message = getReadyDownLoadMessage(false, filePath, fileLength, key, 2);
                sendData(message);
                return;
            }

            String[] path = filePath.split("/");
            
            
            if (path == null) {
                String message = getReadyDownLoadMessage(false, filePath, fileLength, key, 3);
                sendData(message);
                return;
            }
            // 2.2对sd卡存储有一个区别
            String rootPath = "/mnt/sdcard/";
            if (android.os.Build.VERSION.SDK_INT < 8) {
                rootPath = "/sdcard/";
            }
            int length = path.length;
            String name = "";
            boolean success = false;
            // path路径就是以sdcard开始
            int begin=0;
            if(filePath.startsWith("/sdcard"))
            {
                begin=2;
            }else if(filePath.startsWith("/mnt/sdcard"))
            {
                begin=3;
            }
            
            if(begin>=(length-1))
            {
                begin=0;
            }
            
            for (int i = begin; i < length; i++) {               
                
                if ((path[i] == null) || (path[i].trim().equals("")))
                         {
                    continue;
                }
                if (!path[i].contains(".")) {
                    rootPath = rootPath + path[i] + "/";
                    // Log.i("222", "create "+rootPath);
                    success = createDic(rootPath, fileLength, key);
                    if (!success) {
                        break;
                    }
                } else {
                    name = path[i];
                }
            }

            if (!success) {
                return;
            }

            FileThread fileThread = fileThreadMap.get(key);
            if (fileThread != null) {
                long[] sdSpace = SuitUtil.getSdAvailableSpace();
                long availableSpace = sdSpace[0];
                if ((availableSpace >= fileLength)) {
                    boolean result = fileThread.downFile(rootPath + name, fileLength, id);// 检查文件
                    String message = getReadyDownLoadMessage(result, filePath, fileLength, key, 0);
                    sendData(message);
                    return;
                }
            }

            String message = getReadyDownLoadMessage(false, filePath, fileLength, key, 5);
            sendData(message);
            return;
        }
    }

    private boolean createDic(String rootPath, long fileLength, String key) {
        try {
            File file = new File(rootPath);
            if (file.exists() || file.mkdir()) {
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        String message = getReadyDownLoadMessage(false, rootPath, fileLength, key, 4);
        sendData(message);
        return false;
    }

    /**
     * 手机向客户端上传文件-通过启用一个线程开始上传文件。
     * 
     * @param filePath
     * @param key 其实就是端口号。
     */
    public boolean upLoad(final String filePath, final String key) {

        if (fileThreadMap.get(key) == null) {
            return false;
        }

        Runnable task = new Runnable() {
            public void run() {
                FileThread fileThread = fileThreadMap.get(key);
                if (fileThread != null) {
                    fileThread.sendFile(filePath);
                }
            }
        };
        handler.post(task);
        return true;
    }

    /**
     * 默认8851传输通道不能被关闭。
     * 
     * @param key
     */
    public boolean stopFileThread(String key) {
        // if ("8851".equals(key)) {
        // return;
        // }
        return killFileThread(key);
    }

    public boolean startFileThread(int keyPort) {
        return startFileThread(ip, keyPort);
    }
    
    public boolean cancelFileTran(int keyPort)
    {
        FileThread fileThread = fileThreadMap.remove(keyPort);
        if (fileThread != null) {
            fileThread.setFileTranStop();
        }
        return true;
    }

    /*********************************************************************************************************************/

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return myServiceImpl;
    }

    @Override
    public void onStart(Intent paramIntent, int paramInt) {
        super.onStart(paramIntent, paramInt);
        Bundle bundle = paramIntent.getExtras();
        int servicePort = bundle.getInt("server_port");
        ip = bundle.getString("ip");
        startActivity = bundle.getString("class");
        cipherKey = bundle.getString("cipherKey");
        startCommunitionThread(ip, servicePort);
        // 启动一个默认文件传输线程。
        startFileThread(ip, 8851);
        unRegisterSmsReceiver();// onstart 能被调用多次
        registerSmsReceiver();
        title = getString(R.string.app_name);
        connect = getString(R.string.open_mode);
        cancelNotifyIcon();
        notifyIcon();// 会根据不同的启动activity设置不同的Activity

    }

    public void onDestroy() {
        try {
            unRegisterSmsReceiver();
            cancelNotifyIcon();
            handler = null;
            int myPid = android.os.Process.myPid();
            Log.i(TAG, "onDestroy. pid = " + myPid);
            // 把线程停止
            killThread();
            fileThreadMap.clear();
            fileThreadMap = null;
            android.os.Process.killProcess(myPid);
        } catch (Exception e) {
            Log.e(TAG, "SocketService onDestroy exception " + e.getMessage());
        }
    }

    private void registerSmsReceiver() {

        Log.i(TAG, "Register sms and data Receiver");
        try {
            // 注册通讯广播，主要用来接受其他广播中内容发到客户端，比如业务受到一个短信广播，那么这个广播可以通过本通讯广播发到客户端。
            sendDataReceiver = new SendDataReceive();
            registerReceiver(sendDataReceiver, new IntentFilter(DELIVER_MESSAGE_REPORT_ACTIOIN));
            registerReceiver(sendDataReceiver, new IntentFilter(SEND_MESSAGE_REPORT_ACTIOIN));

            // 注册短信发送与送达广播
            mSendReceiver = new SendReceive();
            registerReceiver(mSendReceiver, new IntentFilter(SMS_SEND_ACTIOIN));
            mDeliverReceiver = new SendReceive();
            registerReceiver(mDeliverReceiver, new IntentFilter(SMS_DELIVERED_ACTION));

            // 注册短信接收广播
            mReceiver = new DeliverReceive();
            registerReceiver(mReceiver, new IntentFilter(SMS_RECEIVED_ACTIOIN));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void unRegisterSmsReceiver() {
        Log.i(TAG, "UnRegister sms and data Receiver");
        try {
            if (sendDataReceiver != null) {
                unregisterReceiver(sendDataReceiver);
            }
            if (mSendReceiver != null) {
                unregisterReceiver(mSendReceiver);
            }
            if (mDeliverReceiver != null) {
                unregisterReceiver(mDeliverReceiver);
            }
            if (mReceiver != null) {
                unregisterReceiver(mReceiver);
            }
            mSendReceiver = null;
            mDeliverReceiver = null;
            sendDataReceiver = null;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取可以开始下载的指令返回消息。
     * 
     * @param ok 准备下载是否ok。没有问题true,1表示sdcard不可用;2文件路径是null;3格式不对;4创建路径不成功;5空间不够
     * @param fileName
     * @param fileLength
     * @return
     */
    private String getReadyDownLoadMessage(boolean ok, String fileName, long fileLength,
            String key, int code) {
        StringBuilder returnMessage = new StringBuilder();
        returnMessage.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
        returnMessage.append("<root><action>SaveFile</action><data>");
        returnMessage.append("<fileName>" + fileName + "</fileName>");
        returnMessage.append("<fileLength>" + fileLength + "</fileLength>");
        returnMessage.append("<key>" + key + "</key>");
        returnMessage.append("<result>" + ok + "</result>");
        returnMessage.append("<errorcode>" + code + "</errorcode>");
        returnMessage.append("</data></root>");
        Log.i("222", returnMessage.toString());
        return returnMessage.toString();
    }

    /**
     * 启动通讯进程。
     * 
     * @param ip
     * @param sercicePort
     */
    private void startCommunitionThread(String ip, int sercicePort) {
        try {
            if (socketThread == null) {
                socketThread = new Communition(ip, sercicePort, this, cipherKey);
                socketThread.start();
                Log.i(TAG, "socketThread start " + ip + "sercicePort" + sercicePort);
            }
            return;
        } catch (Exception e) {
            Log.e(TAG, e.getMessage());
        }

    }

    /**
     * 杀死通讯线程。
     */
    private void killThread() {

        killCommunitionThread();
        killAllFileThread();
    }

    private void killCommunitionThread() {
        if (socketThread != null) {
            try {
                socketThread.interrupt();
            } catch (Exception e) {
                Log.e(TAG, "socketThread.interrupt exception ");
            } finally {
                socketThread = null;
            }
        }
    }

    /**
     * 停止所有文件传输线程。
     */
    private void killAllFileThread() {
        for (String key : fileThreadMap.keySet()) {
            killFileThread(key);
        }
    }

    /**
     * 启动通讯进程。
     * 
     * @param ip
     * @param sercicePort
     */
    private boolean startFileThread(String ip, int port) {
        try {
            String key = String.valueOf(port);
            FileThread fileThread = fileThreadMap.get(key);
            if (fileThread == null) {
                fileThread = new FileThread(ip, port, this);
                fileThreadMap.put(key, fileThread);
                fileThread.start();
                Log.i(TAG, "fileThread start " + ip + "sercicePort" + port);
            }
            return true;
        } catch (Exception e) {
            Log.e(TAG, e.getMessage());
            return false;
        }

    }

    /**
     * 单独停止默认线程,并从map中移除。
     * 
     * @param key
     */
    private boolean killFileThread(String key) {
        FileThread fileThread = fileThreadMap.remove(key);
        if (fileThread != null) {
            try {
                fileThread.interrupt();
            } catch (Exception e) {
                Log.e(TAG, key + "fileThread exception ");
            } finally {
                fileThread = null;
            }
        }
        return true;
    }

    private void notifyIcon() {
        try {

            // SharedPreferences shPre = getSharedPreferences("PcSuitPhone",
            // Context.MODE_PRIVATE);
            // if (!shPre.getString("haveStartSocket", "notSet").equals("ok")) {
            // return;
            // }

            NotificationManager notiMa = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            Notification myNo = new Notification();
            myNo.icon = R.drawable.icon;

            myNo.when = System.currentTimeMillis();
            myNo.flags = Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT;
            Intent intent = null;
            if (startActivity.equals("WifiActivity")) {
                intent = new Intent(this.getApplicationContext(), WifiActivity.class);
                myNo.tickerText = "WIFI " + connect;
            } else if (startActivity.equals("HotActivity")) {
                intent = new Intent(this.getApplicationContext(), HotActivity.class);
                myNo.tickerText = "HOT " + connect;

            } else {
                intent = new Intent(this.getApplicationContext(), PhoneServiceAllActivity.class);
                myNo.tickerText = "USB " + connect;
            }
            intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
            PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, 0);
            myNo.setLatestEventInfo(this, title, myNo.tickerText, contentIntent);
            notiMa.notify(1010, myNo);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void cancelNotifyIcon() {
        try {
            NotificationManager notiMa = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            notiMa.cancel(1010);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String cipherKey = "asdfghjk";

    private String connect = "";

    private String title = "";

    private Communition socketThread;

    private String ip = "127.0.0.1";

    private String startActivity = "PhoneServiceAllActivity";

    private HashMap<String, FileThread> fileThreadMap = new HashMap<String, FileThread>();

    private MyServiceImpl myServiceImpl = new MyServiceImpl();

    private static final String TAG = "SocketService";

    private SendReceive mSendReceiver, mDeliverReceiver;

    private DeliverReceive mReceiver;

    private static String SMS_RECEIVED_ACTIOIN = "android.provider.Telephony.SMS_RECEIVED";

    private static String SMS_SEND_ACTIOIN = "SMS_SEND_ACTIOIN";

    private static String SMS_DELIVERED_ACTION = "SMS_DELIVERED_ACTION";

    /*************************************************************************************/

    Handler handler = new Handler() {
    };

    public class MyServiceImpl extends IMyService.Stub {
        /**
         * 这个主要是用来主动上报的。
         */
        @Override
        public boolean setMessage(String value) throws RemoteException {
            return sendData(value);
        }

    }

    /*****************************************************************************************/

    private SendDataReceive sendDataReceiver;

    public static String DELIVER_MESSAGE_REPORT_ACTIOIN = "DELIVER_MESSAGE_REPORT_ACTIOIN";

    public static String SEND_MESSAGE_REPORT_ACTIOIN = "SEND_MESSAGE_REPORT_ACTIOIN";

    public static String SEND_DATA_KEY = "SEND_DATA";

    public class SendDataReceive extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            Log.v(TAG, "receiver action:" + intent.getAction());
            if (intent != null) {
                if (DELIVER_MESSAGE_REPORT_ACTIOIN.equals(intent.getAction())) {
                    String data = intent.getStringExtra(SEND_DATA_KEY);
                    if (data != null) {
                        Log.v(TAG, "SendDataReceive deliver data" + data);
                        sendData(data);
                    }
                } else if (SEND_MESSAGE_REPORT_ACTIOIN.equals(intent.getAction())) {
                    String data = intent.getStringExtra(SEND_DATA_KEY);
                    if (data != null) {
                        Log.v(TAG, "SendDataReceive send data,data is " + data);
                        sendData(data);
                    }
                }
            }
        }
    }

}
